package common;

import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

public class DateUtils
{
	public static final String COMMON_DATE_TIME_FORMAT = "yyyyMMddHHmmss" ;
	public static final String EXT_DATE_TIME_FORMAT = "yyyyMMddHHmmssSSS" ;


	public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
	
	/**
	 * Base ISO 8601 Date format yyyyMMdd i.e., 20021225 for the 25th day of
	 * December in the year 2002
	 */
	public static final String ISO_DATE_FORMAT = "yyyyMMdd";

	/**
	 * Expanded ISO 8601 Date format yyyy-MM-dd i.e., 2002-12-25 for the 25th
	 * day of December in the year 2002
	 */
	public static final String ISO_EXPANDED_DATE_FORMAT = "yyyy-MM-dd";

	/**
	 * Basic ISO 8601 Time format HHmmssSSSzzz i.e., 143212333-500 for 2 pm 32
	 * min 12 secs 333 mills -5 hours from GMT 24 hour clock
	 */
	public static final String ISO_TIME_FORMAT = "HHmmssSSSzzz";

	/**
	 * Basic ISO 8601 Time format HH:mm:ss,SSSzzz i.e., 14:32:12,333-500 for 2
	 * pm 32 min 12 secs 333 mills -5 hours from GMT 24 hour clock
	 */
	public static final String ISO_EXPANDED_TIME_FORMAT = "HH:mm:ss,SSSzzz";

	/**
	 * Base ISO 8601 Date format yyyyMMddTHHmmssSSSzzz i.e.,
	 * 20021225T143212333-500 for the 25th day of December in the year 2002 at 2
	 * pm 32 min 12 secs 333 mills -5 hours from GMT
	 */
	public static final String ISO_DATE_TIME_FORMAT = "yyyyMMdd'T'HHmmssSSSzzz";

	/**
	 * Base ISO 8601 Date format yyyy-MM-ddTHH:mm:ss,SSSzzz i.e.,
	 * 2002-12-25T14:32:12,333-500 for the 25th day of December in the year 2002
	 * at 2 pm 32 min 12 secs 333 mills -5 hours from GMT
	 */
	public static final String ISO_EXPANDED_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss,SSSzzz";

	public static final DateFormatSymbols dateFormatSymbles;

	private static final String[][] foo;

	private static final int JAN_1_1_JULIAN_DAY = 1721426; // January 1, year 1
															// (Gregorian)

	private static final int EPOCH_JULIAN_DAY = 2440588; // Jaunary 1, 1970
															// (Gregorian)

	private static final int ONE_SECOND = 1000;

	private static final int ONE_MINUTE = 60 * ONE_SECOND;

	private static final int ONE_HOUR = 60 * ONE_MINUTE;

	private static final long ONE_DAY = 24 * ONE_HOUR;

	static
	{
		foo = new String[0][];
		dateFormatSymbles = new DateFormatSymbols();
		dateFormatSymbles.setZoneStrings(foo);
	}

	public static final boolean isLeapYear(String isoString, boolean expanded)
			throws ParseException
	{
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTime(isoToDate(isoString, expanded));

		return cal.isLeapYear(cal.get(Calendar.YEAR));
	}

	public static final boolean isLeapYear(String isoString)
			throws ParseException
	{
		return isLeapYear(isoString, false);
	}

	public static final TimeZone getTimeZoneFromDateTime(String date,
			boolean expanded) throws ParseException
	{
		SimpleDateFormat formatter;

		if (expanded)
			formatter = new SimpleDateFormat(ISO_EXPANDED_DATE_FORMAT,dateFormatSymbles);
		else
			formatter = new SimpleDateFormat(ISO_DATE_FORMAT, dateFormatSymbles);

		formatter.parse(date);

		return formatter.getTimeZone();
	}

	public static final TimeZone getTimeZoneFromDateTime(String date)
			throws ParseException
	{
		return getTimeZoneFromDateTime(date, false);
	}

	public static final String add(String isoString, int field, int amount,
			boolean expanded) throws ParseException
	{
		Calendar cal = GregorianCalendar.getInstance();
		cal.setTime(isoToDate(isoString, expanded));
		cal.add(field, amount);

		return dateToISO(cal.getTime(), expanded);
	}

	public static final String add(String isoString, int field, int amount)
			throws ParseException
	{
		return add(isoString, field, amount, false);
	}

	public static final String dateToStandard(Date date)
	{
		SimpleDateFormat formatter;

		formatter = new SimpleDateFormat(DATE_FORMAT, dateFormatSymbles);

		return formatter.format(date);
	}
	
	public static final Date StandardStrTodate(String date)
	{
		SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT, dateFormatSymbles);

		try {
			return formatter.parse(date);
		} catch (ParseException e) {
			e.printStackTrace();
			return null ;
		}
	}
	
	
	public static final String dateToISO(Date date, boolean expanded)
	{
		SimpleDateFormat formatter;

		if (expanded)
			formatter = new SimpleDateFormat(ISO_EXPANDED_DATE_FORMAT,dateFormatSymbles);
		else
			formatter = new SimpleDateFormat(ISO_DATE_FORMAT, dateFormatSymbles);

		return formatter.format(date);
	}

	public static final String dateToStr()
	{
		return dateToStr( new Date() ) ;
	}

	public static final String dateToStr(Date date)
	{
		SimpleDateFormat formatter;

		formatter = new SimpleDateFormat(COMMON_DATE_TIME_FORMAT, dateFormatSymbles);

		return formatter.format(date);
	}

	public static final String dateToISO()
	{
		return dateToISO( new Date() ) ;
	}

	public static final String dateToISO(Date date)
	{
		return dateToISO(date, false);
	}

	public static final long dateToJulianDay(Date date)
	{
		return millisToJulianDay(date.getTime());
	}

	public static final long daysBetween(String isoEarly, String isoLate,
			boolean expanded) throws ParseException
	{
		Calendar c1 = Calendar.getInstance();
		Calendar c2 = Calendar.getInstance();
		c1.setTimeZone(getTimeZoneFromDateTime(isoEarly, expanded));
		c1.setTime(isoToDate(isoEarly, expanded));
		c2.setTimeZone(getTimeZoneFromDateTime(isoLate, expanded));
		c2.setTime(isoToDate(isoLate, expanded));

		return millisToJulianDay(c2.getTime().getTime())
				- millisToJulianDay(c1.getTime().getTime());
	}

	public static final Date isoToDate(String dateString, boolean expanded)
			throws ParseException
	{
		SimpleDateFormat formatter;

		if (expanded)
			formatter = new SimpleDateFormat(ISO_EXPANDED_DATE_FORMAT,dateFormatSymbles);
		else
			formatter = new SimpleDateFormat(ISO_DATE_FORMAT, dateFormatSymbles);

		return new Date(formatter.parse(dateString).getTime());
	}

	public static final Date isoToDate(String dateString) throws ParseException
	{
		return isoToDate(dateString, false);
	}

	public static final Date toDate(String dateString)
	{
		try
		{
			SimpleDateFormat formatter;
			if( dateString.length() == 14 )
				formatter = new SimpleDateFormat(COMMON_DATE_TIME_FORMAT, dateFormatSymbles);
			else
				formatter = new SimpleDateFormat(EXT_DATE_TIME_FORMAT , dateFormatSymbles) ;
	
			return new Date(formatter.parse(dateString).getTime());
		}
		catch( ParseException err )
		{
			throw new RuntimeException( err ) ;
		}
	}

	public static final java.sql.Date isoToSQLDate(String dateString,
			boolean expanded) throws ParseException
	{
		SimpleDateFormat formatter;

		if (expanded)
			formatter = new SimpleDateFormat(ISO_EXPANDED_DATE_FORMAT,dateFormatSymbles);
		else
			formatter = new SimpleDateFormat(ISO_DATE_FORMAT, dateFormatSymbles);

		return new java.sql.Date(formatter.parse(dateString).getTime());
	}

	public static final java.sql.Date isoToSQLDate(String dateString)
			throws ParseException
	{
		return isoToSQLDate(dateString, false);
	}

	public static final Time isoToTime(String dateString, boolean expanded)
			throws ParseException
	{
		SimpleDateFormat formatter;

		if (expanded)
			formatter = new SimpleDateFormat(ISO_EXPANDED_TIME_FORMAT,dateFormatSymbles);
		else
			formatter = new SimpleDateFormat(ISO_TIME_FORMAT, dateFormatSymbles);

		return new Time(formatter.parse(dateString).getTime());
	}

	public static final Time isoToTime(String dateString) throws ParseException
	{
		return isoToTime(dateString, false);
	}

	public static final Timestamp isoToTimestamp(String dateString,
			boolean expanded) throws ParseException
	{
		SimpleDateFormat formatter;

		if (expanded)
			formatter = new SimpleDateFormat(ISO_EXPANDED_DATE_TIME_FORMAT,dateFormatSymbles);
		else
			formatter = new SimpleDateFormat(ISO_DATE_TIME_FORMAT,dateFormatSymbles);

		return new Timestamp(formatter.parse(dateString).getTime());
	}

	public static final Timestamp isoToTimestamp(String dateString)
			throws ParseException
	{
		return isoToTimestamp(dateString, false);
	}

	public static final java.sql.Date julianDayCountToDate(long julian)
	{
		return new java.sql.Date(julianDayToMillis(julian));
	}

	public static final Date julianDayToDate(long julian)
	{
		return new Date(julianDayToMillis(julian));
	}

	public static final long julianDayToMillis(long julian)
	{
		return (julian - EPOCH_JULIAN_DAY + JAN_1_1_JULIAN_DAY) * ONE_DAY;
	}

	public static final long millisToJulianDay(long millis)
	{
		return EPOCH_JULIAN_DAY - JAN_1_1_JULIAN_DAY + (millis / ONE_DAY);
	}

	public static final String roll(String isoString, int field, boolean up,
			boolean expanded) throws ParseException
	{
		Calendar cal = GregorianCalendar.getInstance(getTimeZoneFromDateTime(isoString, expanded));
		cal.setTime(isoToDate(isoString, expanded));
		cal.roll(field, up);

		return dateToISO(cal.getTime(), expanded);
	}

	public static final String roll(String isoString, int field, boolean up)
			throws ParseException
	{
		return roll(isoString, field, up, false);
	}

	public static final String timeToISO(Time date, boolean expanded)
	{
		SimpleDateFormat formatter;

		if (expanded)
			formatter = new SimpleDateFormat(ISO_EXPANDED_TIME_FORMAT,dateFormatSymbles);
		else
			formatter = new SimpleDateFormat(ISO_TIME_FORMAT, dateFormatSymbles);

		return formatter.format(date);
	}
	
	public static final String timeToStr()
	{
		return timeToStr( new Date() ) ;
	}

	public static final String timeToStr(Date date)
	{
		SimpleDateFormat formatter;

		formatter = new SimpleDateFormat(EXT_DATE_TIME_FORMAT, dateFormatSymbles);

		return formatter.format(date);
	}

	public static final String timeToISO(Time date)
	{
		return timeToISO(date, false);
	}

	public static final String timestampToISO(Timestamp date, boolean expanded)
	{
		SimpleDateFormat formatter;

		if (expanded)
			formatter = new SimpleDateFormat(ISO_EXPANDED_DATE_TIME_FORMAT,dateFormatSymbles);
		else
			formatter = new SimpleDateFormat(ISO_DATE_TIME_FORMAT,dateFormatSymbles);

		return formatter.format(date);
	}

	public static final String timestampToISO(Timestamp date)
	{
		return timestampToISO(date, false);
	}

	public static final float toJulian(Calendar c)
	{
		int Y = c.get(Calendar.YEAR);
		int M = c.get(Calendar.MONTH);
		int D = c.get(Calendar.DATE);
		int A = Y / 100;
		int B = A / 4;
		int C = 2 - A + B;
		float E = (int) (365.25f * (Y + 4716));
		float F = (int) (30.6001f * (M + 1));
		float JD = (C + D + E + F) - 1524.5f;

		return JD;
	}

	public static final float toJulian(Date date)
	{
		Calendar c = Calendar.getInstance();
		c.setTime(date);

		return toJulian(c);
	}

	protected static final float normalizedJulian(float JD)
	{
		float f = Math.round(JD + 0.5f) - 0.5f;

		return f;
	}
	
	public static XMLGregorianCalendar toXMLGregorianCalendar(Date date) 
	{

        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        XMLGregorianCalendar gc = null;
        try 
        {
            gc = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
        } catch (Exception e) 
        {
             e.printStackTrace();
        }
        return gc;
    }
 
    public static Date XMLGregorianCalendar2Date(XMLGregorianCalendar cal)
    {
         GregorianCalendar ca = cal.toGregorianCalendar();
         return ca.getTime();
    }
    
    public static String XMLGregorianCalendar2Str(XMLGregorianCalendar cal)
    {
         GregorianCalendar ca = cal.toGregorianCalendar();
         return DateUtils.dateToStandard(ca.getTime()) ;
    }
    
    public static Date getEndOfMonth()
    {
    	Calendar cale = Calendar.getInstance();   
    	cale.set( Calendar.MONTH, cale.get( Calendar.MONTH)+1) ;
    	cale.set(Calendar.DAY_OF_MONTH, 0 );
    	cale.set( Calendar.HOUR_OF_DAY, 0 );
    	cale.set( Calendar.MINUTE, 0 );
    	cale.set( Calendar.SECOND, 0 );
    	cale.set( Calendar.MILLISECOND, 0 );
    	return cale.getTime() ;
    }
    
    
}

